package com.tang.framework.delay.support;

import com.tang.framework.delay.DelayQueue;
import com.tang.framework.delay.support.domain.DelayMethod;
import org.redisson.api.RedissonClient;
import org.springframework.boot.context.event.ApplicationReadyEvent;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.LinkedList;

/**
 * @Author tang jun liang
 * @Date 2023/4/16 15:53
 */

public class DelayContext implements Serializable {



    private final LinkedList<Runnable> runnableList = new LinkedList<>();

    public DelayContext(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
        this.delayExecute = new DelayExecute(redissonClient, this);
        this.delayFinalExecute = new DelayFinalExecute(redissonClient);


    }



    private final RedissonClient redissonClient;

    private final DelayExecute delayExecute;


    private final DelayFinalExecute delayFinalExecute;


    public void processBean(Object bean) {
        runnableList.add(
                () -> {
                    Class<?> clazz = bean.getClass();
                    Method[] methodList = clazz.getDeclaredMethods();
                    for (Method method : methodList) {
                        if (method.isAnnotationPresent(DelayQueue.class)) {
                            DelayQueue delayQueue = method.getAnnotation(DelayQueue.class);
                            processDelayMethod(delayQueue, method, bean);
                        }
                    }
                });
    }

    private void processDelayMethod(DelayQueue delayQueue, Method method, Object bean) {
        DelayMethod delayMethod = DelayMethod
                .builder()
                .targetMethod(method)
                .bean(bean)
                .properties(DelayMethod.Config.builder()
                        .name(delayQueue.name())
                        .retry(delayQueue.retry())
                        .retryIntervalTime(delayQueue.retryIntervalTime())
                        .timeUnit(delayQueue.timeUnit())
                        .enableTransaction(delayQueue.enableTransaction())
                        .build()).build();
        delayExecute.addDelayConfig(delayQueue, method, bean, delayMethod);

    }

    public void doProcessBean() {
        runnableList.forEach(delayExecute::executeRunnable);
        runnableList.clear();
    }

    public void run(ApplicationReadyEvent applicationReadyEvent) {
        delayExecute.run(applicationReadyEvent);
    }
}
